package com.flute.search.service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.flute.framework.Flute;
import com.flute.framework.FluteMonitor;
import com.flute.framework.exception.ConfigurationParseException;
import com.flute.framework.exception.SearchException;
import com.flute.framework.monitor.EventLogger;
import com.flute.framework.monitor.MonitedValue;
import com.flute.framework.search.ISearcher;
import com.flute.framework.search.SearchFilter;
import com.flute.framework.search.SearchRequest;
import com.flute.framework.search.result.ResultInfo;
import com.flute.framework.search.result.SearchResult;
import com.flute.search.bean.DataRecordField;
import com.flute.search.bean.Field;
import com.flute.search.bean.FieldFilter;
import com.flute.search.bean.Search;
import com.flute.search.bean.Searcher;
import com.flute.search.constants.SearchServiceConstants;
import com.flute.search.util.Constant;
import com.flute.search.util.XmlObjectUtil;
import com.flute.tools.util.ExceptionUtil;

public class ViewSearchService extends HttpServlet {

	private static final long serialVersionUID = 1234226435396221696L;

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// info("搜索服务开始...");

		response.setCharacterEncoding(SearchServiceConstants.CHARSET_UTF8);

		String searcher = request.getParameter(SearchServiceConstants.SEARCHER);
		// info("搜索器是" + searcher);

		String keyword = request.getParameter(SearchServiceConstants.KEYWORD);
		// info("关键字是" + keyword);

		String page = request.getParameter(SearchServiceConstants.PAGE);
		// info("页数是" + page);

		String num = request.getParameter(SearchServiceConstants.NUM);
		// info("每页显示数量是" + num);

		String sorter = request.getParameter(SearchServiceConstants.SORTER);
		// info("排序方式是" + sorter);

		Map<String, String> filterMap = new ConcurrentHashMap<String, String>();

		// 初始化过滤器的Map
		initFilterMap(request, filterMap);

		// 检查参数
		if (isNullOrEmpty(searcher) || isNullOrEmpty(keyword)
				|| isNullOrEmpty(page) || isNullOrEmpty(num)) {
			request.setAttribute("exception",
					"无效的参数,searcher,keyword,page,num参数不能为空,请检查再试");
			request.getRequestDispatcher("exception.jsp").forward(request,
					response);
			return;
		}

		try {
			ISearcher searcher1 = Flute.getInstance().getSearcher(searcher);
			if (searcher1 == null) {
				request.setAttribute("exception", "不能找到对应的searcher" + searcher
						+ "，请检查后再试");
				request.getRequestDispatcher("exception.jsp").forward(request,
						response);
				return;
			}
			// 设置SearchRequest
			SearchRequest sr = populateSearchRequest(searcher, keyword, page,
					num, sorter, filterMap);

			SearchResult result = searcher1.nakeSearch(sr);
			setViewData(request, result);
		} catch (ConfigurationParseException e) {
			error("配置解析器异常:" + ExceptionUtil.getExceptionContent(e));
			request.setAttribute("exception", "配置解析器异常");
			request.getRequestDispatcher("exception.jsp").forward(request,
					response);
			return;
		} catch (SearchException e) {
			error("搜索异常" + ExceptionUtil.getExceptionContent(e));
			request.setAttribute("exception", "搜索异常");
			request.getRequestDispatcher("exception.jsp").forward(request,
					response);
			return;
		} catch (Exception e) {
			error("系统异常" + ExceptionUtil.getExceptionContent(e));
			request.setAttribute("exception", "系统异常");
			request.getRequestDispatcher("exception.jsp").forward(request,
					response);
			return;
		}
		// 分页参数
		request.setAttribute("page", page);
		request.setAttribute("pagesize", num);
		request.getRequestDispatcher("view.jsp").forward(request, response);
	}

	private void setViewData(HttpServletRequest request, SearchResult result)
			throws ConfigurationParseException {
		String searcher = request.getParameter(SearchServiceConstants.SEARCHER);
		String showAll = request.getParameter("showAll");// 是否显示全部字段
		// 得到所有的搜索器
		String[] types = Flute.getInstance().getAllSearchers();
		Searcher xmlSearcher = xmlToSearcher();
		List<Search> searches = xmlSearcher.getSearcher(types);

		// 添加字段
		Map<String, String> caption = new TreeMap<String, String>();
		for (String field : result.getAllProperties()) {
			caption.put(field, result.getPropertyValue(field));
		}
		// 添加数据
		DataRecordField record = new DataRecordField();
		Set<String> fieldSet = new TreeSet<String>();
		List<List<String>> allValueList = new ArrayList<List<String>>();
		int i = 0;
		for (ResultInfo info : result.getInfoList()) {
			i++;
			if (i == 1) {
				fieldSet = getFields(xmlSearcher, result, info, showAll,
						searcher);
			}
			List<String> valueList = new ArrayList<String>();
			for (String field : fieldSet) {
				String value = info.getPropertyValue(field);
				valueList.add(value);
			}
			allValueList.add(valueList);
		}
		record.setFields(fieldSet);
		record.setValues(allValueList);

		request.setAttribute("searches", searches);
		request.setAttribute("caption", caption);
		request.setAttribute("record", record);
		// 记录总数
		request.setAttribute("total", caption.get("length") == null ? "0"
				: caption.get("length"));
	}

	private Set<String> getFields(Searcher searcherAlias, SearchResult result,
			ResultInfo info, String showAll, String searcher) {
		Set<String> title = new TreeSet<String>();
		if (isNullOrEmpty(showAll)) {
			String alias = searcherAlias.getAlias(searcher);// 根据searcher得到alias
			if (alias != null) {
				FieldFilter fieldFilter = xmlToFieldFilter();
				List<Field> tempFields = fieldFilter.getFieldsByAlias(alias);// 根据alias得到fields
				if (tempFields != null) {
					for (Field f : tempFields) {
						for (String field : info.getAllProperties()) {
							if (field.equals(f.getName())) {
								title.add(field);
								break;
							}
						}
					}
				}
			}
		} else {
			for (String field : info.getAllProperties()) {
				title.add(field);
			}
		}
		return title;
	}

	private FieldFilter xmlToFieldFilter() {
		String xml = XmlObjectUtil.readXml(Constant.SHOW_FIELD_XMLPATH);
		return XmlObjectUtil.fromXml(FieldFilter.class, xml);
	}

	private Searcher xmlToSearcher() {
		String xml = XmlObjectUtil.readXml(Constant.SEARCHER_ALIAS_XMLPATH);
		return XmlObjectUtil.fromXml(Searcher.class, xml);
	}

	private void error(String message) {
		EventLogger.error(new MonitedValue(message),
				FluteMonitor.getSearcherKey());
	}

	@SuppressWarnings("unused")
	private void info(String message) {
		EventLogger.info(new MonitedValue(message),
				FluteMonitor.getSearcherKey());
	}

	private SearchRequest populateSearchRequest(String searcher,
			String keyword, String page, String num, String sorter,
			Map<String, String> filterMap) throws UnsupportedEncodingException {
		// 设置SearchFilter
		SearchRequest sr = new SearchRequest();
		sr.setKeyword(keyword);
		sr.setNumberPerPage(Integer.parseInt(num));
		sr.setPageNumber(Integer.parseInt(page));
		setSorter(sorter, sr);
		sr.setSearcherName(searcher);
		setFilter(filterMap, sr);
		return sr;
	}

	private void setFilter(Map<String, String> filterMap, SearchRequest sr) {
		if (!filterMap.isEmpty()) {
			SearchFilter filter = populateFilter(filterMap);
			sr.setSearchFilter(filter);
		}
	}

	private void setSorter(String sorter, SearchRequest sr) {
		if (!isNullOrEmpty(sorter)) {
			sr.setSorter(sorter);
		}
	}

	private SearchFilter populateFilter(Map<String, String> filterMap) {
		SearchFilter filter = new SearchFilter();
		for (Entry<String, String> entry : filterMap.entrySet()) {
			String[] values = entry.getValue().split(",");
			for (String value : values) {
				filter.addFilter(entry.getKey(), value);
			}
		}
		return filter;
	}

	@SuppressWarnings("unchecked")
	private void initFilterMap(HttpServletRequest request,
			Map<String, String> filterMap) {
		Enumeration<String> names = request.getParameterNames();
		while (names.hasMoreElements()) {
			String name = names.nextElement();
			String prefix = SearchServiceConstants.FILTER
					+ SearchServiceConstants.UNDERLINE;
			if (name.startsWith(prefix)) {
				String fieldName = name.substring(7);
				if (filterMap.containsKey(fieldName)) {
					String value = filterMap.get(fieldName) + ","
							+ request.getParameter(name);
					filterMap.put(fieldName, value);
				} else {
					filterMap.put(fieldName, request.getParameter(name));
				}
			}
		}
	}

	private boolean isNullOrEmpty(String s) {
		return s == null || s.trim().equals(SearchServiceConstants.EMPTY);
	}

}
